package com.example.service.impl;

import java.time.LocalDateTime;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.common.ErrorCode;
import com.example.constant.AlgorithmConstant;
import com.example.constant.UserConstant;
import com.example.exception.BusinessException;
import com.example.model.po.User;
import com.example.mapper.UserMapper;
import com.example.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.utils.AlgorithmUtils;
import com.example.utils.MD5Utils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author LinHui
 * @since 2024-03-28
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private UserMapper userMapper;


    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword) {
        log.info("账户注册开始~");
        //账号不能小于4位
        if (userAccount == null || userAccount.length() < 4) {
            log.info("账户注册出现异常，账户账号为空或者长度小于4位~");
            // todo 修改为自定义异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号为空/账号长度不够");
        }

        //密码不能小于8位
        if (userPassword == null || userPassword.length() < 8) {
            log.info("账户注册出现异常，账户密码为空或者长度小于8位~");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码为空/密码长度不够");
        }

        //账号不能包括特殊字符
        String pattern = "^[a-zA-Z0-9_]+$";
        Matcher matcher = Pattern.compile(pattern).matcher(userAccount);
        if (!matcher.find()) {
            log.info("账户注册出现异常，账户账号出现特殊字符~");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号出现特殊字符");
        }

        //密码必须和校验密码相同
        if (!userPassword.equals(checkPassword)) {
            log.info("账户注册出现异常，俩次密码输入不同~");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户输入的密码和校验密码不同");
        }

        //账号不能重复
        boolean exists = lambdaQuery().
                eq(User::getUserAccount, userAccount).
                exists();

        if (exists) {
            log.info("账户注册出现异常，数据库中已有该账户~");
            throw new BusinessException(ErrorCode.USER_EXISTE);
        }

        //对密码进行加密

        String alPassword = MD5Utils.encrypt(UserConstant.SALT + userPassword, AlgorithmConstant.MD5);


        User user = new User();
        user.setUsername(userAccount);
        user.setUserAccount(userAccount);
        user.setAvatarUrl("https://pic.imeitou.com/uploads/allimg/221012/8-221012092201.jpg");
        user.setGender(1);
        user.setUserPassword(alPassword);
        user.setUserStatus(0);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setIsDelete(0);
        // todo 用户身份，默认为0，普通用户
        user.setUserRole(0);


        //向数据库中插入数据
        boolean Result = save(user);
        //if (!Result) {
        //    throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号异常，账户密码为空或者长度小于8位~");
        //}
        log.info("id为{}的用户注册成功~", user.getId());
        return user.getId();
    }

    @Override
    public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        log.info("用户登录~");
        //账号不能小于4位
        if (userAccount == null || userAccount.length() < 4) {
            log.info("用户账号异常，账号为空或者长度小于4位");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号异常");
        }

        //密码不能小于8位
        if (userPassword == null || userPassword.length() < 8) {
            log.info("用户账号异常，账户密码为空或者长度小于8位~");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号异常，账户密码为空或者长度小于8位~");
        }

        //账号不能包括特殊字符
        String pattern = "^[a-zA-Z0-9_]+$";
        Matcher matcher = Pattern.compile(pattern).matcher(userAccount);
        if (!matcher.find()) {
            log.info("用户账号异常，账户账号出现特殊字符~");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号异常，账户账号出现特殊字符~");
        }


        //账号不能重复

        userPassword = MD5Utils.encrypt(UserConstant.SALT + userPassword, AlgorithmConstant.MD5);
        User user = lambdaQuery().
                eq(User::getUserAccount, userAccount).
                eq(User::getUserPassword, userPassword).
                one();

        if (user == null) {
            log.info("用户账号异常，用户密码错误~请检查账号和密码是否正确");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号异常，用户密码错误~请检查账号和密码是否正确");
        }


        //脱敏，隐藏敏感信息

        User safteUser = getSafteUser(user);

        //记录用户的登录状态
        HttpSession session = request.getSession();
        session.setAttribute(UserConstant.USER_LOGIN_STATE, safteUser);


        log.info("id为{}的用户登录成功~", user.getId());
        return safteUser;
    }


    @Override
    public User getSafteUser(User orgUser) {

        if (orgUser == null) {
            return null;
        }

        User safetUser = new User();
        safetUser.setId(orgUser.getId());           //用户id
        safetUser.setUsername(orgUser.getUsername());   //用户姓名
        safetUser.setUserAccount(orgUser.getUserAccount());     //账号
        safetUser.setAvatarUrl(orgUser.getAvatarUrl());     //头像
        safetUser.setGender(0);     //性别
        safetUser.setProfile(orgUser.getProfile());
        //safetUser.setUserPassword("");
        safetUser.setPhone(orgUser.getPhone());     //电话
        safetUser.setEmail(orgUser.getEmail());     //邮箱
        safetUser.setUserStatus(0);     //用户状态，是否被封号
        safetUser.setCreateTime(orgUser.getCreateTime());       //创建时间
        safetUser.setUserRole(orgUser.getUserRole());       //用户权限/角色
        safetUser.setUpdateTime(new Date());
        //safetUser.setIsDelete(0);
        safetUser.setTags(orgUser.getTags());
        return safetUser;
    }


    /**
     * 根据标签搜索用户
     * 将所有用户全部存入内存，然后通过 stream() 来进行分析取数据
     *
     * @param tagList
     * @return
     */
    @Override
    public List<User> searchUsersByTags(List<String> tagList) {

        if (CollectionUtils.isEmpty(tagList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Gson gson = new Gson();
        return this.lambdaQuery().list().stream().filter(user -> {
            ////如果当前用户没有标签，直接过滤掉
            //if (user.getTags() == null) {
            //    return false;
            //}

            //获取当前用户标签，然后将其转成list集合
            String tags = user.getTags();
            Set<String> tempTagName = gson.fromJson(tags, new TypeToken<Set<String>>() {
            }.getType());

            tempTagName = Optional.ofNullable(tempTagName).orElse(new HashSet<>());

            //查看当前用户是否存在要搜索的标签
            for (String tag : tagList) {
                if (tempTagName.contains(tag)) {
                    return true;
                }
            }

            return false;
        }).map(this::getSafteUser).collect(Collectors.toList());

    }

    @Override
    public int updateUser(User user, User loginUser) {
        long userId = user.getId();
        //如果要修改的用户id小于0，那无论是谁，都不用修改了
        if (user == null && userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //要修改用户信息的人，既不是修改的自己信息，也不是管理员
        if (!isMy(user, loginUser)) {
            if (!isAdmin(loginUser)) {
                throw new BusinessException(ErrorCode.NO_AUTH);
            }
        }

        int count = userMapper.updateById(user);
        if (count <= 0) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }

        return count;

    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        if (request == null) {
            return null;
        }

        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);

        if (userObj == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }

        return (User) userObj;

    }

    @Override
    public List<User> matchUsers(long num, User loginUser) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "tags");
        queryWrapper.isNotNull("tags");
        List<User> userList = this.list(queryWrapper);
        String tags = loginUser.getTags();
        Gson gson = new Gson();
        List<String> tagList = gson.fromJson(tags, new TypeToken<List<String>>() {
        }.getType());
        // 用户列表的下标 => 相似度
        List<Pair<User, Long>> list = new ArrayList<>();
        // 依次计算所有用户和当前用户的相似度
        for (int i = 0; i < userList.size(); i++) {
            User user = userList.get(i);
            String userTags = user.getTags();
            // 无标签或者为当前用户自己
            if (StringUtils.isBlank(userTags) || user.getId() == loginUser.getId()) {
                continue;
            }
            List<String> userTagList = gson.fromJson(userTags, new TypeToken<List<String>>() {
            }.getType());
            // 计算分数
            long distance = AlgorithmUtils.minDistance(tagList, userTagList);
            list.add(new Pair<>(user, distance));
        }
        // 按编辑距离由小到大排序
        List<Pair<User, Long>> topUserPairList = list.stream()
                .sorted((a, b) -> (int) (a.getValue() - b.getValue()))
                .limit(num)
                .collect(Collectors.toList());
        // 原本顺序的 userId 列表
        List<Long> userIdList = topUserPairList.stream().map(pair -> pair.getKey().getId()).collect(Collectors.toList());
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.in("id", userIdList);
        // 1, 3, 2
        // User1、User2、User3
        // 1 => User1, 2 => User2, 3 => User3
        Map<Long, List<User>> userIdUserListMap = this.list(userQueryWrapper)
                .stream()
                .map(user -> getSafteUser(user))
                .collect(Collectors.groupingBy(User::getId));
        List<User> finalUserList = new ArrayList<>();
        for (Long userId : userIdList) {
            finalUserList.add(userIdUserListMap.get(userId).get(0));
        }
        return finalUserList;

    }


    /**
     * 使用sql语句直接查询
     *
     * @param tagList
     * @return
     */
    @Deprecated
    private List<User> searchUsersByTagsSQL(List<String> tagList) {

        if (CollectionUtils.isEmpty(tagList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<User> qw = new QueryWrapper<>();


        for (String tag : tagList) {
            qw = qw.like("tags", tag);
        }

        Gson gson = new Gson();

        List<User> list = userMapper.selectList(qw);
        return list.stream().map(this::getSafteUser).collect(Collectors.toList());
    }





    /**
     * 判断当前用户是否为自己登录
     * 例：当要修改数据时，当前用户只能修改自己的数据，而管理员则可以修改任意用户数据
     *
     * @param user
     * @param loginUser
     * @return
     */
    public boolean isMy(User user, User loginUser) {

        //用户在不是管理员的情况下，修改的是其它用户信息
        if (user.getId() != loginUser.getId()) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }

        return true;
    }


    /**
     * 是否为管理员
     *
     * @param request
     * @return
     */
    @Override
    public boolean isAdmin(HttpServletRequest request) {
        // 仅管理员可查询
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        User user = (User) userObj;
        return user != null && user.getUserRole() == UserConstant.ADMIN_ROLE;
    }

    @Override
    public boolean isAdmin(User loginUser) {
        return loginUser != null && loginUser.getUserRole() == UserConstant.ADMIN_ROLE;
    }


}
